package apijson

import (
	"context"

	"github.com/glennliao/apijson-go/action"
	"github.com/glennliao/apijson-go/config"
	"github.com/glennliao/apijson-go/model"
	"github.com/glennliao/apijson-go/query"
)

// 插件接口 定义插件安装方法
type 插件接口 interface {
	A安装(上下文 context.Context, apiJson *APIJSON)
}

// APIJSON 主结构体
type APIJSON struct {
	P配置   *config.P配置结构
	T调试模式 bool // 是否开启调试模式，显示每步骤
	S上下文  context.Context

	D动作钩子列表  []action.G钩子
	D动作钩子映射表 map[string][]*action.G钩子
}

// 默认APIJSON实例
var 默认APIJSON = X新建()

// 新建 创建一个新的APIJSON实例
func X新建() *APIJSON {
	实例 := &APIJSON{}
	实例.P配置 = config.X新建配置()
	实例.S上下文 = context.Background()
	return 实例
}

// 加载 为默认APIJSON加载多个应用，简化使用
func J加载(应用列表 ...func(上下文 context.Context, a *APIJSON)) *APIJSON {
	for _, 应用 := range 应用列表 {
		默认APIJSON.S使用(应用)
	}
	默认APIJSON.J加载配置()
	return 默认APIJSON
}

// 使用 添加中间件函数
func (a *APIJSON) S使用(中间件 ...func(上下文 context.Context, a *APIJSON)) *APIJSON {
	for _, 插件 := range 中间件 {
		插件(a.S上下文, a)
	}
	return a
}

// 加载配置 重新加载APIJSON的配置
func (a *APIJSON) J加载配置() {
	a.P配置.C重新加载()
}

// 获取配置 返回配置对象
func (a *APIJSON) H获取配置() *config.P配置结构 {
	return a.P配置
}

// 新建查询 创建一个新的查询对象
func (a *APIJSON) X新建查询(上下文 context.Context, 请求参数 model.Map) *query.C查询结构体 {
	查询 := query.X新建查询(上下文, a.H获取配置().H获取查询配置(), 请求参数)

	查询.S数据库元数据 = a.P配置.S数据库元信息
	查询.S数据库字段风格 = a.P配置.S数据库字段风格
	查询.Json字段风格 = a.P配置.JSON字段风格

	查询.B不验证访问 = a.P配置.F访问控制.J禁用验证
	查询.F访问条件 = a.P配置.F访问控制.T条件处理函数

	return 查询
}

// 新建动作 创建一个新的Action对象
func (a *APIJSON) X新建动作(上下文 context.Context, 方法 string, 请求参数 model.Map) *action.C操作 {
	动作 := action.X新建操作(上下文, a.H获取配置().H获取操作配置(), 方法, 请求参数)

	动作.B不验证访问权限 = a.P配置.F访问控制.J禁用验证
	动作.S数据库字段风格 = a.P配置.S数据库字段风格
	动作.JSON字段风格 = a.P配置.JSON字段风格

	动作.X新建查询 = a.X新建查询
	动作.G钩子映射 = a.D动作钩子映射表

	return 动作
}

// 注册动作钩子 注册一个action.Hook
func (a *APIJSON) Z注册动作钩子(钩子 action.G钩子) {
	if a.D动作钩子映射表 == nil {
		a.D动作钩子映射表 = make(map[string][]*action.G钩子)
	}
	for _, 项目 := range 钩子.S适用场景 {
		a.D动作钩子映射表[项目] = append(a.D动作钩子映射表[项目], &钩子)
	}
}
